<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>ArraySizeHelper解析 - Tekkaman - 博客园</title>
<link type="text/css" rel="stylesheet" href="/bundles/blog-common.css?v=d_Et_wtKX7bJcow-mLRlKv4wqGQ2rjNrWTPvZmUqF8Y1"/>
<link id="MainCss" type="text/css" rel="stylesheet" href="/skins/blue/bundle-blue.css?v=rfLrqsg7Ztisg3I5vn34I-ipkS-4hvjSoL1rsleOVtc1"/>
<link title="RSS" type="application/rss+xml" rel="alternate" href="http://www.cnblogs.com/tekkaman/rss"/>
<link title="RSD" type="application/rsd+xml" rel="EditURI" href="http://www.cnblogs.com/tekkaman/rsd.xml"/>
<link type="application/wlwmanifest+xml" rel="wlwmanifest" href="http://www.cnblogs.com/tekkaman/wlwmanifest.xml"/>
<script src="http://common.cnblogs.com/script/jquery.js" type="text/javascript"></script>  
<script type="text/javascript">var currentBlogApp = 'tekkaman', cb_enable_mathjax=false;</script>
<script src="/bundles/blog-common.js?v=dVqr0ue7y29mRAG2afMkFcSk38ChENfNlXrmAf_YHQE1" type="text/javascript"></script>
</head>
<body>
<a name="top"></a>

<div class="pagelayout">
    
<div class="header">
	<div>
		<a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/tekkaman/">Tekkaman</a>
	</div>
	<div>
		
	</div>
</div>
    <div id="leftmenu" class="leftcolumn">
        
            
<h1 class = "listtitle">导航</h1>
<ul class = "list">
			<li class = "listitem"><a id="MyLinks1_HomeLink" class="listitem" href="http://www.cnblogs.com/">博客园</a></li>
			<li class = "listitem"><a id="MyLinks1_MyHomeLink" href="http://www.cnblogs.com/tekkaman/">首页</a>
			<li class = "listitem"><a id="MyLinks1_NewPostLink" rel="nofollow" href="http://i.cnblogs.com/EditPosts.aspx?opt=1">新随笔</a>
			<li class = "listitem"><a id="MyLinks1_ContactLink" accesskey="9" class="listitem" rel="nofollow" href="http://space.cnblogs.com/msg/send/Tekkaman">联系</a></li>
			<li class = "listitem"><a id="MyLinks1_Syndication" class="listitem" href="http://www.cnblogs.com/tekkaman/rss">订阅</a><a id="MyLinks1_XMLLink" href="http://www.cnblogs.com/tekkaman/rss"><img src="http://www.cnblogs.com/images/xml.gif" alt="订阅" /></a>
			<li class = "listitem"><a id="MyLinks1_Admin" class="listitem" rel="nofollow" href="http://i.cnblogs.com/">管理</a></li>
</ul>
            <div id="blog-calendar" style="display:none"></div><script type="text/javascript">loadBlogDefaultCalendar();</script>
            
<div class = "listtitle">统计</div>
	<ul class = "list">
		<li class = "listitem">随笔 - 1048
		<li class = "listitem">文章 - 0
		<li class = "listitem">评论 - 74
		<li class = "listitem">引用 - 0
	</li>
</ul>
            
<div class = "listtitle">公告</div>
	<ul class = "list">
		<li class = "listitem">
			<div id="blog-news"></div><script type="text/javascript">loadBlogNews();</script>
	</li>
</ul>
            <div id="blog-sidecolumn"></div><script type="text/javascript">loadBlogSideColumn();</script>
        
        <div class="spacer">
            &nbsp;</div>
    </div>
    <div class="centercolumn">
        

<div class = "singlepost">
	<div class = "posttitle">
		<a id="cb_post_title_url" class="singleposttitle" href="http://www.cnblogs.com/tekkaman/p/3268518.html">ArraySizeHelper解析</a>
	</div>
    <div class="postbody">
	<div id="cnblogs_post_body"><p>［<span style="color: #ff0000;"><strong>ArraySizeHelper解析</strong></span>］</p>
<p>　　以下代码用于获取一个数组的元素个数，例如 int table[100]，以下宏返回100。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:cpp;gutter:false;">template &lt;typename T, size_t N&gt; 
char (&amp;ArraySizeHelper(const T (&amp;array)[N]))[N]; 
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
</pre>
</div>
<p>&nbsp;［<strong><span style="color: #ff0000;">要点</span></strong>］</p>
<p>　1、数组的引用</p>
<p>　　<span>T (&amp;)[N] (注意：有个括号)。比如：</span><br /><span>　　int a[5] = {0};</span><br /><span>　　int (&amp;ra)[5] = a; 这里ra就是一个对数组a的引用，其这个数组的大小也是5；</span></p>
<p><span>　2、返回值为数组引用的函数</span></p>
<p>　　T (&amp; Fun( param_list ) )[N];<br />　　Fun是一个函数，其返回值类型是 T (&amp;)[N];</p>
<p>　3、<strong><span style="color: #ff0000;">sizeof()在编译期完成，与运行时无关</span></strong></p>
<p>　　<span>sizeof是C/C++语言中的keyword，不是函数。对其参数里的表达式是不会在执行期去执行的，而只是在编译期去推算整个表达式的最后的类型信息。</span><br /><span>　　比如： int a = 1; sizeof(a++); cout &lt;&lt; a;&nbsp;&nbsp; // a还是1. 不会是2；</span><br /><span>　　因为是在编译期完成，编译器只需要类型信息，不需要函数的实现体。所以就可以不用提供定义体。</span><br /><span>　　下面这个例子可能更能说明这个问题。</span><br /><span>　　int Fun(); // only declare it without definition</span><br /><span>　　sizeof( Fun() );&nbsp; // 这里Fun()函数不会在运行的时候被执行，仅仅是在编译时，编译器需要知道的是：Fun()函数返回值的类型是什么。</span></p>
<p><span>　4、模板自动推导在编译期完成</span></p>
<p><span>　　</span>模板推导是由编译器在编译期(compile time)完成的，而不是在执行期(run time)完成的。</p>
<p>　　这个是理解的关键之一。不涉及内存布局分配的问题。编译期间，编译器只关心声明信息(也就是声明式里面所带的类型信息)。模板推导会自动推导模板参数的各种信息(类型，传递过来的数值等)。以下是一个例子：<br />　　template&lt;int x, int y&gt;<br />　　struct sum_<br />　　{<br />&nbsp; 　　enum { value = x + y };<br />　　};<br />　　int sum = sum_&lt;3, 4&gt;::value; // sum的值在编译期间就已经确定下来了，不是在执行期间由CPU运算得到。<br />　　这个例子里的模板，仅仅只有数值的传递，没有包含类型。这个可能大家很少见到的。但是模板是支持的。</p>
<p>　　例子二：<br />　　template&lt; typename T, size_t N&gt;<br />　　void Fun( T (&amp;)[N] );</p>
<p>　　这个模板里既有类型T，又有数值N；模板推导时，是根据Fun的实参来推导得到的。比如：<br />　　int a[5];<br />　　Fun(a); // 编译器经过推导就知道，T=int，N=5。注意这里的N能得到5，是因为Fun的参数声明决定的。这里Fun的参数是：数组引</p>
<div>&nbsp; &nbsp;5、<span style="color: #ff0000;"><strong>sizeof(一个指针)和sizeof(一个数组)有很大区别</strong></span></div>
<div><span><span>　　</span></span></div>
<div><span><span>　　</span></span>int a[5];
<p><em id="__mceDel">　　int *p = a;<br />　　int (*pa)[5] = &amp;a;</em></p>
<p><br />　　// p和pa都是指针，但是指针的类型不同：p的类型是int*；pa的类型是int(*)[5]。</p>
<p><br />　　sizeof(p)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // = 4;<br />　　sizeof(a)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // = 20 = 5*sizeof(int)<br />　　sizeof(*p)&nbsp;&nbsp;&nbsp;&nbsp; // = sizeof(int) = 4;<br />　　sizeof(pa)&nbsp;&nbsp;&nbsp; // = 4;<br />　　sizeof(*pa)&nbsp; // = sizeof(a) = 20;</p>
<p>　6、跨函数类型信息丢失</p>
<p>　　C/C++对于数组和指针是明确区分其类型的。数组的信息包括(类型+大小)，而指针则没有大小信息。<br />　　在这里附带要说一下，<span style="color: #ff0000;"><strong>数组经过函数参数传递后，数组的大小信息就丢失了</strong></span>。比如：<br />　　void Fun( int a[5] )<br />　　{　　&nbsp;<br />&nbsp;&nbsp; 　　　int n = sizeof(a);&nbsp; // n为4，相对于就是sizeof(int*).因为编译器只传递过来了数组的地址，大小信息没有了。<br />　　}</p>
<p><br />　　所以,上面Fun的参数声明里面的数组的具体数字是被忽略掉的。其等价声明式可以是：<br />　　void Fun( int a[10] );<br />　　void Fun( int a[] );<br />　　void Fun( int *a );</p>
<p><br />　　为了需要把大小信息传递到函数里面去，需要额外加一个参数来表示大小信息，这个大小信息需要调用者来提供，并且有调用者来保证大小信息的正确性。<br />　　void Fun( int a[], int size );</p>

</div>
<div>　</div>
<div>　参考I：<a href="http://blog.csdn.net/yuanmanzheng/article/details/5472967">http://blog.csdn.net/yuanmanzheng/article/details/5472967</a></div>
<div>　参考II：<a href="http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx">http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx</a></div>
<p><span>　　</span></p></div><div id="MySignature"></div>
<div class="clear"></div>
<div id="blog_post_info_block">
<div id="BlogPostCategory"></div>
<div id="EntryTag"></div>
<div id="blog_post_info">
</div>
<div class="clear"></div>
<div id="post_next_prev"></div>
</div>


    </div>
	<div class = "itemdesc">
		posted on <span id="post-date">2013-08-19 19:10</span> <a href='http://www.cnblogs.com/tekkaman/'>Tekkaman</a> 阅读(<span id="post_view_count">...</span>) 评论(<span id="post_comment_count">...</span>)  <a href ="http://i.cnblogs.com/EditPosts.aspx?postid=3268518" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(3268518);return false;">收藏</a>
	</div>
</div>
	<script type="text/javascript">var allowComments=true,isLogined=false,cb_blogId=87561,cb_entryId=3268518,cb_blogApp=currentBlogApp,cb_blogUserGuid='dd5c3128-6869-e011-a53f-842b2b196315',cb_entryCreatedDate='2013/8/19 19:10:00';loadViewCount(cb_entryId);</script>
	
<a name="!comments"></a><div id="blog-comments-placeholder"></div><script type="text/javascript">var commentManager = new blogCommentManager();commentManager.renderComments(0);</script>
<div id="comment_form" class="commentform">
<a name="commentform"></a>
<div id="divCommentShow"></div>
<div id="comment_nav"><span id="span_refresh_tips"></span><a href="javascript:void(0);" id="lnk_RefreshComments" onclick="return RefreshCommentList();">刷新评论</a><a href="#" onclick="return RefreshPage();">刷新页面</a><a href="#top">返回顶部</a></div>
<div id="comment_form_container"></div>
<div class="ad_text_commentbox" id="ad_text_under_commentbox"></div>
<div id="site_nav_under"><a href="http://www.cnblogs.com/" target="_blank" title="开发者的网上家园">博客园首页</a><a href="http://q.cnblogs.com/" target="_blank" title="程序员问答社区">博问</a><a href="http://news.cnblogs.com/" target="_blank" title="IT新闻">新闻</a><a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a><a href="http://job.cnblogs.com/" target="_blank">程序员招聘</a><a href="http://kb.cnblogs.com/" target="_blank">知识库</a></div>
<div id="opt_under_post"></div>
<script type="text/javascript">
    var enableGoogleAd = canShowAdsense(); var googletag = googletag || {}; googletag.cmd = googletag.cmd || [];
    fixPostBodyFormat();
</script>
<div id="ad_under_post_holder">
<script type='text/javascript'>
    var googletag = googletag || {};
    googletag.cmd = googletag.cmd || [];
    (function () {
        if (enableGoogleAd) {
            var gads = document.createElement('script');
            gads.async = true;
            gads.type = 'text/javascript';
            var useSSL = 'https:' == document.location.protocol;
            gads.src = (useSSL ? 'https:' : 'http:') + '//www.googletagservices.com/tag/js/gpt.js';
            var node = document.getElementsByTagName('script')[0];
            node.parentNode.insertBefore(gads, node);
        }
    })();
</script>
<script type='text/javascript'>
    try {
        if (enableGoogleAd) {
            googletag.cmd.push(function () {
                googletag.defineSlot('/1090369/cnblogs_blogpost_C1_sitehome', [300, 250], 'div-gpt-ad-1346480159711-0').addService(googletag.pubads());
                googletag.defineSlot('/1090369/cnblogs_blogpost_C2', [468, 60], 'div-gpt-ad-1410860226396-0').addService(googletag.pubads());
                googletag.pubads().enableSingleRequest();
                googletag.enableServices();
            });
        };
    } catch (e) { }
</script>
<div id="google_ad_c1" class="c_ad_block">
    <div id='div-gpt-ad-1346480159711-0' style='width:300px; height:250px;'>
    <script type='text/javascript'>
        try {
            if (enableGoogleAd) {
                googletag.cmd.push(function () { googletag.display('div-gpt-ad-1346480159711-0'); });            
            } else {
                $('#div-gpt-ad-1346480159711-0').hide();
            }
    } catch (e) { }
    </script>
    </div>
</div>
</div>
<div id="under_post_news"></div>
<div id="google_ad_c2" class="c_ad_block">
<div id='div-gpt-ad-1410860226396-0' style='width:468px; height:60px;'>
<script type='text/javascript'>
try {
    if (enableGoogleAd) {
        googletag.cmd.push(function () { googletag.display('div-gpt-ad-1410860226396-0'); });
    } else {
        $('#div-gpt-ad-1346480159711-0').hide();
    }
} catch (e) { }
</script>
</div>
</div>
<div id="under_post_kb"></div>
<div id="HistoryToday" class="c_ad_block"></div>
<script type="text/javascript">
$(function () {
    loadNewsAndKb();
    loadBlogSignature();
    LoadPostInfoBlock(cb_blogId, cb_entryId, cb_blogApp, cb_blogUserGuid);
    GetPrevNextPost(cb_entryId, cb_blogId, cb_entryCreatedDate);
    loadOptUnderPost();
    GetHistoryToday(cb_blogId, cb_blogApp, cb_entryCreatedDate);
    setTimeout(function () { incrementViewCount(cb_entryId); }, 200);
});
</script>
</div>

        <div class="spacer">
            &nbsp;</div>
    </div>
    
<div class="footer">
	Powered by: 
	<br />
	
	<a id="Footer1_Hyperlink3" NAME="Hyperlink1" href="http://www.cnblogs.com/" style="font-family:Verdana;font-size:12px;">博客园</a>
	<br />
	Copyright &copy; Tekkaman
</div>
</div>

</body>
</html>
